問題解説: クソ上司オブザイヤー2018

クソ上司とはクソな上司のことです。今回のクソ上司は自分が納得しないと話に応じてくれないタイプの、いわば頑固な上司でした。
なぜ彼が生まれたかについては諸説ありますが、「ちょっと特殊な技術を触ってみたら思いのほかいろいろな問題を踏み抜いた」というのが実情のようです。
ちなみに当日「クソ神上司」の名札を付けて歩いていた人物はおそらく無関係でしょう。たぶん。

1問目

問題文

最近Webアプリを動かしているサーバーへの負荷が高かったので、業者に頼んで負荷を分散できる構成にしてもらった。
現在は192.168.21.20で動作しているらしいが、どうやらアプリケーションが不安定のようだ。トラブルを解決するためにはいくつかの情報が必要だが、正当な理由なくサーバーへのアクセスが許可されていない。
幸いにも同じセグメントにあるマシンは使えるので、まずはこの負荷分散の名前がどのようなものか知りたい。
このマシンを用いて、負荷分散の名前を理由とともに上司(運営)に報告すること。

注意事項

必ずclientを使うこと。clientを使わずに回答は不可能である。
動作確認にWebブラウザは使わずにcurlなどで確認すること。使った場合の動作は保証されない。

トラブルの概要

負荷分散の形式がわからない(これはトラブルですか?)

解説

最初のトラブル(?)は負荷分散の形式を特定する問題でした。
ポイントとなるのは注意事項にある「必ずclientを使うこと。clientを使わずに回答は不可能である。」の文言です。
同じセグメントにあるマシンを使わないと解けないということは、少なくともL2に関する何かが絡んでいるというところです。この点でピンときたチームもいるのではないでしょうか。

まずcurlなどで192.168.21.20へリクエストを送ってみると、レスポンスが返ってこないことがあるものの、Webページらしきものが見えます。
ここでtcpdumpを使いながらリクエストとレスポンスを眺めると、取得成功時に行きと帰りでMACアドレスが異なっていることに気づきます。
これはDSR (Direct Server Return) と呼ばれる手法で、レスポンスをリアルサーバから直接返すことでLBを経由せず、負荷をかけないようにすることができます。

よってMACアドレスが異なることをふまえた上でDSRであることが指摘できていれば正解です。

2問目

問題文

DSRであることを上司に伝えると、LB1台、アプリケーションサーバー2台という構成であることがわかった。
最初にも述べたが、ブラウザ (Chrome, Firefox, Safariなど) からアクセスすると他のマシンから一切アプリケーションに繋がらない。
DSRであることがわかったのでLBへのアクセスは許可されたが、まだアプリケーションサーバーへのアクセスは許可されていない。上司によると、パケットキャプチャを見ているとアプリケーションサーバーの片方にしかリクエストが来ていないので、負荷分散についてはLBに問題があると疑ってやまないようだ。
LBの設定を調査して、ブラウザからアクセスしても正常に動作するようにしてほしい。たまにレスポンスが返ってこないのはアプリケーションサーバーの問題だと確信しているが、LBの設定を直さないことには上司がアプリケーションサーバーへのアクセスを許可してくれない。

トラブルの概要

192.168.21.20にブラウザで接続したときにそれ以降のリクエストが届かなくなる

解説

この問題ではLBサーバへのアクセスが与えられます。
ログインして設定をいろいろ見てみると、keepalived+ipvsadmでL2DSRを構築していることがわかります。
また、実際にブラウザで192.168.21.20へアクセスしてみると、そのブラウザは繋がるのに他のクライアントからは一切繋がらなくなるという現象に直面します。
まずipvsadmコマンドでLBの状況を確認してみると、

~$ sudo ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.21.20:80 lc
  -> 192.168.21.71:80                Route   1      1          3
  -> 192.168.21.72:80                Route   1      0          4

192.168.21.71:80に対してActiveConnがずっと1になっていることがわかります。
また、スケジューリングアルゴリズムがlc (Least Connection) であることから残りのリクエストがすべて192.168.21.72:80に転送されていることがわかります。

/etc/keepalived/keepalived.confの中身を見ると、

vrrp_instance VI_1 {
  state MASTER
  interface ens3
  virtual_router_id 51
  priority 100
  nopreempt
  advert_int 1
  virtual_ipaddress {
    192.168.21.20
  }
}

virtual_server_group app_servers {
  192.168.21.20 80
}

virtual_server group app_servers {
  delay_loop 10
  lvs_sched rr
  lvs_method DR
  lb_algo lc
  protocol TCP

  real_server 192.168.21.71 80 {
    TCP_CHECK {
      connect_timeout 10
    }
  }
  real_server 192.168.21.72 80 {
    TCP_CHECK {
      connect_timeout 10
    }
  }
}

となっています。注目すべきはvirtual_server group app_serversの中身で、

lvs_sched rr
lb_algo lc

においてlvs_schedおよびlb_algoは全く同じ意味をもつパラメータです。現在はlb_algoは古いパラメータですが、まだ有効であるためlvs_sched rrが上書きされてしまっています。
このことからもスケジューリングアルゴリズムがlcに設定されていることがわかります。

これらの点から、原因はスケジューリングアルゴリズムがlcであることと、ブラウザがずっとコネクションを保持しているために正常に応答が返ってこないもう片方のサーバ(192.168.21.72)へずっとリクエストが転送されていることを指摘できていれば正解です。

3問目

問題文

LBのスケジューリングを指摘したところ、上司はアプリケーションサーバーの片方に問題があることを認めて両方のサーバーへのアクセスを許可してくれた。
VIP192.168.21.20のアプリケーションが正しく動作するように修正してほしい。
また、セキュリティ上の観点から192.168.21.0/26から直接アプリケーションサーバーへHTTPアクセスができないようにして欲しい。
再起動した時も正常な状態が維持されるようにすること。

トラブルの概要

192.168.21.20へのリクエストが返ってこないことがある
192.168.21.{11,12}へのHTTPリクエストが成功する

解説

3問目は2台のリアルサーバへのアクセスが与えられます。
192.168.21.11(app1)と192.168.21.12(app2)の2台存在しますが、いずれもkeepalivedのヘルスチェックを通っているように、LBからのリクエストは正常に行えるため、まずは問題があるサーバを特定するのがスタート地点です。
どちらのサーバにもimgconvというサービスがsystemdで登録されており、/opt/imgconv/imgconvにあるバイナリを起動してこれが80番で動いていることがわかります。
2問目のようにipvsadmコマンドで確認すると、192.168.21.72側へ振り分けられていないことがわかるので、サーバにログインしてapp2(192.168.21.12@ens3, 192.168.21.72@ens4)側が原因であるとわかります。
適当にDSRやkeepalivedで検索すると設定方法が出てきます。やり方はいくつかありますが、app1にはiptables, カーネルパラメータの設定がされていることがわかります。ただしこれらは永続化されていないため、iptables -Lsysctl -aなどで見つける必要があります。
app1に入っていた設定は以下の通りです。

iptables

*nat
-A PREROUTING -d 192.168.21.20/32 -j REDIRECT

sysctl (カーネルパラメータ)

net.ipv4.conf.all.arp_ignore=1
net.ipv4.conf.all.arp_announce=2
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.ens3.rp_filter=0
net.ipv4.conf.ens4.rp_filter=0

iptablesにはVIPへのリクエストをそのまま受け取るための設定が、sysctlにはMACアドレス書き換えに伴ったLinuxのセキュリティ機構を無効化するための設定が書かれています。
これらをapp2も適用するとまずはVIP(192.168.21.20)に対して常にリクエストが返ってくることが確認できます。

次に192.168.21.{11,12}へ直接HTTPリクエストができないようにします。これは単純にiptablesを書くだけで良いです。謝ってtcp/22を閉じて締め出されないようにするのを忘れないでください。

-A INPUT -i ens3 -p tcp --dport 22 -j ACCEPT
-A INPUT -i ens4 -j ACCEPT
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -j DROP

講評

1問目を正解できたチームは2チームのみで、いずれのチームも2問目も突破していました。DSR自体を知っていないと回答するのは難しかったように思います。
よくある誤答としてはVRRPがありました。VRRPはfirst hopで到達するルータが物理的に複数台ある構成のため、今回の問題とは全く関係がありません。keepalivedがVIPを使うためにVRRPを内部で使用しているため、頻繁に飛んでくるVRRPのパケットに気づいてそれについて答えた競技者がかなり多かったようです。
また、VRRPは負荷分散というよりかは冗長化を目的としています。今回のテーマが冗長化であっただけにちょっと意地悪だったかもしれません。ちなみに今回会場提供いただいたさくらインターネット様のサービス「さくらの専用サーバ」のロードバランサーにはDSR・非DSR構成の選択オプションがあります。意図せずしてわかりにくいヒントができてしまったのですが、気づいた方はいらっしゃいましたか?